class Compiler{
	constructor(vm) {
	    this.vm = vm
		this.el = vm.$el
		this.compile(this.el)
	}
	
	// 编译模板 处理文本节点和元素节点
	compile(el){
		let childNodes = el.childNodes
		Array.from(childNodes).forEach(node => {
			// 处理文本节点
			if(this.isTextNode(node)){
				this.compileText(node)
			} else if(this.isElementNode(node)){ // 处理元素节点
				this.compileElement(node)
			}
			
			// 判断当前节点 是否又子节点 若有调用 compile 处理
			if(node.childNodes && node.childNodes.length){
				this.compile(node)
			}
				
		})
	}
	
	// 编译元素节点 处理指令
	compileElement(node){
		// 遍历所以属性节点 
		Array.from(node.attributes).forEach(attr => {
			// 判断是否为指令 'v- ... '
			let attrName = attr.name
			if(this.isDirective(attrName)){
				attrName = attrName.substr(2)
				let key = attr.value
				this.update(node,key,attrName)
			}else if(this.isDirectives(attrName)){ // 判断@click 。。。。。直接调用 this.onUpdater()
				let onName = attrName.substr(1)
				this.onUpdater.call(this,node,this.vm[attr.value],attr.value,onName)
				node.removeAttribute(attrName)
			}
		})
		
	}
	
	update(node,key,attrName){
		let updateFn,onName
		if(attrName.indexOf('on') > -1){
			updateFn = this['on' + 'Updater'] // 拼接处理方法名
			onName = attrName.substr(3)
		}else{
			updateFn = this[attrName + 'Updater'] // 拼接处理方法名
			onName = ''
		}
		updateFn && updateFn.call(this,node,this.vm[key],key,onName) // 判断是否有值
		node.removeAttribute('v-' + attrName)	// 移除v-html、v-model等属性 
	}

	dataFor(item){
		let obj = this.vm.$data
			if(item.indexOf('.') > -1){	// 判断参数是否为对象里的值
				return this.objFor(item,obj)
			}else{
				for(let key in obj){
					if(item === key) return obj[key]
					else return item
				}  
			}   
		
	}

	objFor(item,obj){
		let item1 = item.split(".")
		for(let key in obj){
			if(item1[0] == key){
				let list = []
				for(let i of item1){
					if(i !== item1[0]) list.push(i)
				}
				if(list.length > 0) return this.objFor(list.join('.'),obj[key]) // 递归调用
				else return obj[key]
			}
		} 
	}

	// 处理 v-html
	htmlUpdater(node,value,key){
		node.innerHTML = value
		new Watcher(this.vm,key,(newValue) => {
			node.innerHTML = newValue
		})
	}

	// 处理 v-on @...
	onUpdater(node,value,key,onName){
		// node.addEventListener(onName,value)	// this指向当前dom
		// node.addEventListener(onName,() => {
		// 	return value()	// this指向 window 
		// })
		let parameter = []
		if(key.indexOf('(') > -1){ // 判断是否带参数
			parameter = key.substring(key.indexOf('(') + 1,key.indexOf(')')).split(",")
			key = key.substr(0,key.indexOf('('))
			parameter.forEach((item,i) => {
				parameter[i] = this.dataFor(item) // 判断参数是否为data里的值 
			})
		}
		node.addEventListener(onName,() => {
			return this.vm[key](...parameter)	// this指向初始化的vue对象 
		})
		
		new Watcher(this.vm,key,(newValue) => {
			node.addEventListener(onName,() => {
				return this.vm[key]()
			})
		})
	}

	

	// 处理 v-text
	textUpdater(node,value,key){
		node.textContent = value
		new Watcher(this.vm,key,(newValue) => {
			node.textContent = newValue
		})
	}
	// 处理 v-model
	modelUpdater(node,value,key){
		node.value = value
		new Watcher(this.vm,key,(newValue) => {
			node.value = newValue
		})
		// 双向绑定
		node.addEventListener('input',() => {
			this.vm[key] = node.value
		})
	}
	
	// 编译文本节点 处理差值表达式
	compileText(node){
		// console.dir(node)
		// {{ 名字 }}
		let reg = /\{\{(.+?)\}\}/ 
		let value = node.textContent
		if(reg.test(value)){
			let key = RegExp.$1.trim()
			node.textContent = value.replace(reg,this.vm[key])
			// 创建watcher对象 当数据改变更新视图
			new Watcher(this.vm,key,(newValue) => {
				node.textContent = newValue
			})
		}
		
	}
	
	// 判断元素属性是否为指令
	isDirective(atterName){
		return atterName.startsWith('v-')
	}
	
	// 判断元素属性是否为指令@
	isDirectives(atterName){
		return atterName.startsWith('@')
	}

	// 判断节点属性是否为文本节点
	isTextNode(node){
		return node.nodeType === 3 // 3 为文本节点 
	}
	
	// 判断节点属性是否为元素节点
	isElementNode(node){
		return node.nodeType === 1 // 1 为元素节点 
	}
}

